"""
Pairs minigame.

Player is shown a number of cards face up, containing a number of pairs.
The cards are then flipped over and the player has a set amount of time and
number of guesses in order to match up all the pairs of cards.

"""

#  Copyright 2010 Nick Ryder.

#  This file is part of Minigame Mayhem.

#  Minigame Mayhem is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.

#  Minigame Mayhem is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.

#  You should have received a copy of the GNU General Public License
#  along with Minigame Mayhem.  If not, see <http://www.gnu.org/licenses/>.


import pygame
import os
from pygame.locals import *
import time
import sys
import random
import os
cwd = os.getcwd()
corepath = os.path.split(cwd)[0]
corepath = os.path.join(corepath, "core")
sys.path.append(corepath)
import minigame
import spritesheet

class Card:
   "Playing card class."

   def __init__(self, back, face):
      #starting with just blocks of colour, will do images later.
      self.face = face
      self.back = back
      self.width = 30
      self.height = 70
      self.surface = pygame.Surface((self.width, self.height))
      self.rect = self.surface.get_rect()
      self.state = None    # Str: "faceup" or "facedown"
      self.pair = None
      self.solved = False
      self.faceup()

   def place(self, center):
      "Position of center of card."
      self.rect.center = center

   def setsize(self, height, width):
      "Set size of card."
      self.height = height
      self.width = width
      self.surface = pygame.surface(self.width, self.height)
      self.rect = self.surface.get_rect()
      if self.state == "faceup":
         self.faceup()
      elif self.state == "facedown":
         self.facedown()

   def faceup(self):
      "Set card face up."
      self.surface.blit(self.face, (0, 0))
      self.state = "faceup"

   def facedown(self):
      "Set card face down."
      self.surface.blit(self.back, (0, 0))
      self.state = "facedown"

   def setpair(self, card):
      "Set the card's pair."
      self.pair = card

   def checkpair(self, card):
      "Check if card is pair of this card."
      if self.pair == card:
         return True
      else:
         return False

class PairsMinigame(minigame.Minigame):
   "Pairs Minigame class."

   def __init__(self, screen, level=0):
      minigame.Minigame.__init__(self, screen, level)
      self.developers = ["Nick Ryder"]
      self.testers = ["Nick Ryder"]
      self.artists = ["Nick Ryder"]
      self.cards = []
      if level in [0, 1]:
         self.cardnumber = 8
         self.guesses = 7
         self.showtime = 5
         self.guesstime = 15
      if level in [2, 3]:
         self.cardnumber = 16
         self.guesses = 15
         self.showtime = 5
         self.guesstime = 30
      if level >= 4:
         self.cardnumber = 24
         self.guesses = 30
         self.showtime = 7
         self.guesstime = 80 
      self.currentcard = None # Card that has been selected.
      self.background = pygame.Surface(self.screen.get_size())
      self.backgroundcolour = (100, 200, 200)
      self.background.fill(self.backgroundcolour)
      self.screen.blit(self.background, (0, 0))
      random.seed()

   def load(self):
      "Load images."
      # Will use this when there are some images on the cards.
      
      pass

   def start(self):
      "show start screen."
      message = "Match up pairs of cards."
      font = pygame.font.Font(None, 40)
      message = font.render(message, 1, (0, 0, 0))
      messagerect = message.get_rect(centerx = self.screen.get_width()/2, 
         centery = self.screen.get_height()/2)
      self.screen.blit(self.background, (0, 0))
      self.screen.blit(message, messagerect)
      pygame.display.flip()
      time.sleep(3)

   def showcards(self):
      "Initiate and show cards face up."
      # Create cards
      self.cards = []
      sprites = spritesheet.SpriteSheet(os.path.join(self.datapath, "pairssprites.bmp"))
      images = []
      for y in range(3):
         for x in range(5):
            rect = pygame.Rect(x * (30 + 1) + 1, y * (70 + 1) + 1, 30, 70)
            images.append(sprites.get_image(rect))
      for card in range(self.cardnumber / 2):
         r = random.randint(0, 255)
         g = random.randint(0, 255)
         b = random.randint(0, 255)
         card1 = Card(images[0], images[card + 1])
         card2 = Card(images[0], images[card + 1])
         card1.setpair(card2)
         card2.setpair(card1)
         self.cards.append(card1)
         self.cards.append(card2)
      # Position cards.
      positions = []
      for x in range(6):
         for y in range(4):
            positions.append(( x * 100 + 50, y * 100 + 50))
      for card in self.cards:
         number = random.randint(0, len(positions) - 1)
         card.place(positions[number])
         positions.remove(positions[number])
      self.screen.blit(self.background, (0, 0))
      for card in self.cards:
         self.screen.blit(card.surface, card.rect)
      pygame.display.flip()
      # Show cards for a given time."
      starttime = time.time()
      currenttime = time.time()
      timegone = currenttime - starttime
      while timegone < self.showtime:
         currenttime = time.time()
         timegone = currenttime - starttime
         for event in pygame.event.get():
            if event.type == QUIT:
               sys.exit()
            elif event.type == KEYDOWN:
               if event.key == K_ESCAPE:
                  sys.exit()
   

   def main(self):
      "User tries to pair up cards."
      self.showcards()
      for card in self.cards:
         card.facedown()
         self.screen.blit(card.surface, card.rect)
      pygame.display.flip()
      infofont = pygame.font.Font(None, 30)
      timesurf = pygame.Surface(infofont.size("Time Left: 30s"))
      timerect = timesurf.get_rect(right = self.screen.get_width(),
         bottom = self.screen.get_height())
      guesssurf = pygame.Surface(infofont.size("Guesses left: 20"))
      guessrect = guesssurf.get_rect(bottom = timerect.top - 5,
         right = self.screen.get_width())
      timesurf.fill(self.backgroundcolour)
      guesssurf.fill(self.backgroundcolour)
      starttime = time.time()
      currenttime = time.time()
      timegone = currenttime - starttime
      while timegone < self.guesstime:
         currenttime = time.time()
         timegone = currenttime - starttime
         timeremaining = self.guesstime - timegone
         timemsg = "Time left: %ds" % (timeremaining + 1)
         timemsg = infofont.render(timemsg, 1, (0, 0, 0))
         self.screen.blit(timesurf, timerect)
         self.screen.blit(timemsg, timerect)
         guessmsg = "Guesses left: %d" % self.guesses
         guessmsg = infofont.render(guessmsg, 1, (0, 0, 0))
         self.screen.blit(guesssurf, guessrect)
         self.screen.blit(guessmsg, guessrect)
         pygame.display.flip()
         for event in pygame.event.get():
            if event.type == QUIT:
               sys.exit()
            elif event.type == KEYDOWN:
               if event.key == K_ESCAPE:
                  sys.exit()
            elif event.type == MOUSEBUTTONDOWN:
               x, y = pygame.mouse.get_pos()
               for card in self.cards:
                  if card.rect.collidepoint(x, y) and card.solved != True:
                     card.faceup()
                     self.screen.blit(card.surface, card.rect)
                     pygame.display.flip()
                     time.sleep(0.2)
                     if self.currentcard == None:
                        self.currentcard = card
                     else:
                        self.guesses -= 1
                        if self.currentcard.checkpair(card):
                           card.solved = True
                           self.currentcard.solved = True
                        else:
                           self.currentcard.facedown()
                           card.facedown()
                           self.screen.blit(card.surface, card.rect)
                           self.screen.blit(self.currentcard.surface, 
                              self.currentcard.rect)
                           pygame.display.flip()
                           if self.guesses == 0:
                              timegone = self.guesstime + 1
                        self.currentcard = None

   def finish(self):
      "Finishing screen with result."
      self.win = True
      for card in self.cards:
         if card.solved != True:
            self.win = False
      if self.win == True:
         message = "You won!"
      else:
         message = "You lost."
      font = pygame.font.Font(None, 40)
      message = font.render(message, 1, (0, 0, 0))
      messagerect = message.get_rect(centerx = self.screen.get_width()/2, 
         centery = self.screen.get_height()/2)
      self.screen.blit(self.background, (0, 0))
      self.screen.blit(message, messagerect)
      pygame.display.flip()
      time.sleep(3)

if __name__ == "__main__":
   random.seed()
   pygame.init()
   screen = pygame.display.set_mode((800, 600))
   pygame.display.set_caption("Pairs Minigame")
   if len(sys.argv) == 2:
      try:
         level = int(sys.argv[1])
      except ValueError:
         print "Argument must be level (int)"
         sys.exit()
   else:
      level = random.randint(0, 5)
   pm = PairsMinigame(screen, level)
   pm.run()
